#pragma once
#include "../../PocelainMacro.h"
#include "../../core/Ref.h"
#include "OpenGLShader.h"
#include "../EUniformType.h"
#include "../Uniform.h"
POCELAIN_NAMESPACE_BEGIN
class POCELAIN_EXPORT OpenGLShaderProgram : public Ref
{
public:
    struct ShaderCompileContext
    {
        std::map<std::string,EUniformType> attributes;
        std::map<std::string,std::string> defines;
    };
    typedef std::map<std::string,std::string> defines_t;
    OpenGLShaderProgram();
    ~OpenGLShaderProgram();
    OpenGLShaderProgram(OpenGLShaderProgram &&other);
    OpenGLShaderProgram &operator=(OpenGLShaderProgram &&other);
    OpenGLShaderProgram(const OpenGLShaderProgram &other)=delete;
    OpenGLShaderProgram &operator=(const OpenGLShaderProgram &other)=delete;
    void swap(OpenGLShaderProgram &other);
    void clear();
    bool isValid()const;
    GLuint getProgramId()const{return mProgramId;}
    GLint getAttributeLocation(const std::string &attrName);
    void enableVertexAttributeArray(const std::string &attrName);
    void enableVertexAttributeArray(GLint location);
    void disableVertexAttributeArray(const std::string &attrName);
    void disableVertexAttributeArray(GLint location);
    GLint getUniform(const std::string &uniName);
    void use();
    bool linkProgram(
        OpenGLShader *vert,
        OpenGLShader *frag,
        const defines_t &defines,
        const std::map<std::string,EUniformType> &attributeTypeMap,
        const std::map<std::string,EUniformType> &uniformMap
        );
    bool linkProgram(
        OpenGLShader *tess,
        OpenGLShader *Geometry,
        OpenGLShader *vert,
        OpenGLShader *frag,
        const defines_t &defines,
        const std::map<std::string,EUniformType> &attributeTypeMap,
        const std::map<std::string,EUniformType> &uniformMap);
private:
    bool compileShader(
        OpenGLShader *shader,
        const defines_t &defines,
        const std::map<std::string,EUniformType> &attributeTypeMap,
        const std::map<std::string,EUniformType> &uniformMap);

    // valid program id is non-zero
    GLuint mProgramId = 0;
};
POCELAIN_NAMESPACE_END
